﻿#include "filepath.h"

PathZXC::PathZXC(){
    this->PathZXC_Init();
}
PathZXC::~PathZXC(){}
void PathZXC::PathZXC_Init(){
    if (debugall) {
        if(!this->completepath.empty())
            this->allfilepaths = this->GetAllFiles(this->completepath, ZFP::FILE_PATH_LIST::FILE_PATH_COM);
    }
    if (this->splitflag&&(!this->completepath.empty())) {
        this->_pathsplit(this->completepath, this->drive, this->folderpath, this->lastname, this->extendname);
    }    
}

/*--------------------------------路径标准化------------------------------------->>>
函数名：PathNormalize
目的：主要针对“\\”和“/”形式的路径表达不统一问题。
功能：对输入的路径inpath转化为指定的标准形式，如将所有的“/”转化为“\\”
*/
void PathZXC::PathNormalize(std::string& inpath, std::string swapto){
    std::string bereplaced = "/";
    if (swapto == "/")
        bereplaced = "\\";
    this->StringReplace(inpath, (const std::string)bereplaced, (const std::string)swapto);
}

void PathZXC::PathNormalize(std::string& inpath){
    this->PathNormalize(inpath, "/");
}
/*string的字串替换，即将输入str中的指定部分替换为目标子串*/
void PathZXC::StringReplace(std::string& inputstr, const std::string bereplaced, const std::string replacedto) {
    size_t index;
    index = inputstr.find_first_of(bereplaced);
    while (index>=0&&index< inputstr.length()) {
        inputstr.replace(index, 1, replacedto); //用str替换指定字符串从起始位置pos开始长度为len的字符 
        index = inputstr.find_first_of(bereplaced);
    }
}

/*--------------------------------路径检测-是否存在---------------------------->>>
函数名：pathexists
功能：当路径存在时返回true，不存在时返回false;

*/
bool PathZXC::pathexists(std::string path){
    if (_access(path.c_str(), 0)) 
        return false;
    return true;
}

/*-----------------------------------路径创建---------------------------------->>>
函数名：pathmkdir
功能：将逐级对不存在的路径进行创建，对输入的不存在路径进行创建，如已存在则直接返回1，创建失败返回-1，否则返回0；
注意：该函数只创建路径，因此输入必须为具体的文件夹路径，而非某个文件路径。
    -当前仅在windows上通过测试
*/
char PathZXC::pathmkdir(std::string path){
    if (this->pathexists(path))  //如果路径已存在
        return ZFP::FILE_PATH_MKDIR::MAKE_DIR_EXISTS;
    PathNormalize(path);             //先进行路径的标准化，防止路径格式错乱
    size_t index;
    string folder,tempfolder=path;
    index = tempfolder.find_first_of("/");
    while (0<index&&index<path.length()) {
        //inputstr.replace(index, 1, replacedto);
        folder = path.substr(0, index);
        if (!this->pathexists(folder))   //如果不存在
            if (_mkdir(folder.c_str())) {  //如果创建成功则继续，否则返回-1
#ifdef PathZXC_DEBUG
                cout << folder << "create folder failed!" << endl;
#endif
                return ZFP::FILE_PATH_MKDIR::MAKE_DIR_FAILED;
            }
        tempfolder.replace(index, 1, "*");
        index = tempfolder.find_first_of("/");
    }
    if (_mkdir(path.c_str())) {  //如果创建成功则继续，否则返回-1
#ifdef PATHZXC_DEBUG
        if (debugall)
            std::cout << path << "create folder failed!" << std::endl;
#endif
        return ZFP::FILE_PATH_MKDIR::MAKE_DIR_FAILED;
    }
    return ZFP::FILE_PATH_MKDIR::MAKE_DIR_SUCCESS;
}

/*
函数名：GetAllFiles
功能：含默认（完整文件路径）参数的文件路径获取函数，将获取指定路径下的所有文件路径

*/
vector<string> PathZXC::GetAllFiles(uchar flag){
    if (this->completepath.empty()||!this->pathexists(this->completepath)) {
        if (debugall)
            std::cout << this->completepath << "-is empty or not exists!" << endl;
#ifdef PATHZXC_DEBUG
        if (debugall)
            std::cout << this->completepath << "输入路径为空或不存在！" << endl;
#endif
        return this->allfilepaths;
    }
    this->_FilesList(this->completepath, this->allfilepaths,"*",flag);
    return this->allfilepaths;
}
/*
函数名：GetAllFiles
功能：含参数的完整文件路径获取函数，将获取指定路径下的文件路径(包括子目录)

*/
std::vector<std::string> PathZXC::GetAllFiles(std::string inpath, uchar flag){
    this->completepath = inpath;
    return this->GetAllFiles(flag);
}

void PathZXC::MYPathSplit(std::string inpath, std::string & drive, std::string & folder, std::string & name, std::string & evtname) {
    if(debugall)
        cout << "查找文件路径：\n";
    this->_pathsplit(inpath, drive, folder, name, evtname);
}

/*-----------------------------------路径分割---------------------------------->>>
函数名：_pathplit
功能：对指定输入的路径分割为盘符、路径、名称、后缀名
参数：
    -inpath         //输入路径
    -drive          //盘符
    -folder         //路径（除去盘符）
    -name           //文件名称（不带后缀名）
    -evtname        //后缀名
*/
void PathZXC::_pathsplit(std::string inpath, std::string& drive, std::string& folder, std::string& name, std::string& evtname){
    if (!this->pathexists(inpath)) {    //路径不存在
        if (debugall)
            std::cout << "warning: the input path is not exists!--" << inpath << endl;
    }
    int index = inpath.find_first_of("\\");    
    if (index > 0 && index < inpath.length()) { //路径标准化，防止
        this->PathNormalize(inpath,"/");
    }
    if ((!inpath.find_first_of("/"))) {
        if (debugall)
            std::cout << "Can not split PATH:" << inpath << endl;
        return;
    }
    int index_p = inpath.find_last_of(".");
    index = inpath.find_first_of("/");
    drive = string(inpath, 0, index);
    index = inpath.find_last_of("/");
    if (index_p > 0 && index_p<inpath.length() && index_p>index)
        folder = string(inpath, drive.length(), index - drive.length() + 1);
    else {
        folder = string(inpath, drive.length(), inpath.length() - drive.length() + 1);
        return;
    }
    name = string(inpath, drive.length() + folder.length(), index_p - drive.length() - folder.length());
    evtname = string(inpath, drive.length() + folder.length() + name.length(), inpath.length() - drive.length() - folder.length() - name.length());
}

/*
函数名：_FilesList
功能：获取指定路径下的文件路径
规则：
    可以指定某一类文件，如只需要“.jpg”文件，则需设置fileclass参数为“*.jpg”，若只需要保存文件名称，则可设置对应的flag

参数：
    -path       指定路径
    -files      结果
    -fileclass  查找类型，当前可设置:*(所有)、*.*(非文件夹)、*.png(png图片)等
    -flag       标记位，当前可设置FILE_PATH_COMPLETE（1，完整路径）、FILE_PATH_NAME（2，文件名称）、FILE_PATH_SKIP_SUB（4，跳过子目录）三类
注意：当查找*.*、*.png等具体的文件时，仅会在所输入的目录下查找，而不会在次级目录下查找。
*/
void PathZXC::_FilesList(std::string path, std::vector <std::string>& files, std::string fileclass="*", uchar flag = ZFP::FILE_PATH_LIST::FILE_PATH_COM) {
#ifdef WIN
    intptr_t  hFile = 0;
    struct _finddata_t fileinfo;
    std::string pathp;

    this->StringReplace(path, "\\", "/");
    if ((hFile = _findfirst(pathp.assign(path).append("/"+ fileclass).c_str(), &fileinfo)) != -1)    {       
        do {
            if ((fileinfo.attrib & _A_SUBDIR))   {  // 子目录
                if (flag&ZFP::FILE_PATH_LIST::FILE_PATH_SKIP_SUB)   // 跳过子目录
                    continue;
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)  {
                    _FilesList(pathp.assign(path).append("/").append(fileinfo.name), files, fileclass, flag);
                }
            }   
            else   {    // 普通文件、隐藏文件、系统文件、只读文件分别对应_A_NORMAL、_A_HIDDEN、_A_SYSTEM、_A_RDONLY
                string filestr = fileinfo.name;
                if(flag&ZFP::FILE_PATH_LIST::FILE_PATH_COM)         // 保存完整路径
                    files.push_back(pathp.assign(path).append("/").append(filestr));
                else
                    if(flag&ZFP::FILE_PATH_LIST::FILE_PATH_NAME)    // 仅保存文件名称
                        files.push_back(filestr);
            }
        } while (_findnext(hFile, &fileinfo) == 0);
        _findclose(hFile);
    }
#else
    DIR* pDir;   //  是头文件<dirent.h>的类型
    struct dirent* ptr;  // opendir、readdir这些都是头文件dirent.h
    if (!(pDir = opendir(path.c_str()))) return;
    while ((ptr = readdir(pDir)) != 0) {
        // strcmp是C语言里的，只导入string,然后std::strcmp都是没有的
        if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
            if (flag & ZFP::FILE_PATH_LIST::FILE_PATH_COM)         //保存完整路径
                files.push_back(path + "/" + ptr->d_name);
            else
                if (flag & ZFP::FILE_PATH_LIST::FILE_PATH_NAME)    //仅保存文件名称
                    files.push_back(ptr->d_name);
        }
    }
    closedir(pDir);
#endif
}

